/*
  THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
  ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED
  TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
  PARTICULAR PURPOSE.

  Copyright (c) 2003-2009 PRO ACTIVE SAS - www.proactive-group.com
   
  Ref_DesFire.c
  -------------

  This is the reference applications that validates the whole SpringProx API
  for Philips DESFire cards (reentrant version)
  
  JDA 11/12/2008 : forked from ref_desfire.c

*/
#include "products/springprox/springprox_ex.h"
#include "cardware/desfire/sprox_desfire_ex.h"

#include <time.h>
#include <stdio.h>

#ifdef __linux__
#include <sys/time.h>
#endif

void DesFire_xDES_Recv(BYTE * data, WORD blocks, const BYTE * key);

//#define LOOP_TEST

#ifdef WIN32
#ifdef LOOP_TEST
#define CHECK_RC() { if (rc!=0) { Beep(880,1000); printf("\nline %d - failed (%d) %s\n", __LINE__-1, rc, SPROXx_Desfire_GetErrorMessage(rc)); err_count++; goto tag_halt; } printf("."); fflush(NULL); }
#else
#define CHECK_RC() { if (rc!=0) { printf("\nline %d - failed (%d) %s\n", __LINE__-1, rc, SPROXx_Desfire_GetErrorMessage(rc)); goto tag_halt; } printf("."); fflush(NULL); }
#endif
#endif

#ifdef __linux__
#define CHECK_RC() { if (rc!=0) { printf("\nline %d - failed (%d) %s\n", __LINE__-1, rc, SPROXx_Desfire_GetErrorMessage(rc)); goto tag_halt; } printf("."); fflush(NULL); }
#endif

#ifdef LOOP_TEST
WORD loop_count = 0;
WORD err_count = 0;
#endif

/* Les cles utilises dans ce test */
const BYTE abNullKey[16] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
const BYTE ab1DesKey[16] = { "ABCDEFGHABCDEFGH" };
const BYTE ab3DesKey[16] = { "Card Master Key!" };

const BYTE ab3DesTestKey[16] = { "ABCDEFGHIJKLMNOP" };

/* Budrate in each direction */
BYTE want_dsi_dri = 0;

int main(int argc, char **argv)
{
  SWORD rc;
  int i;
  char s_buffer[64];
  BYTE cid = 0xFF;
  BYTE atq[2];
  BYTE sak[1];
  BYTE snr[12];
  BYTE snrlen = 12;
  BYTE ats[32];
  BYTE atslen = 32;
  
  SPROX_INSTANCE rInst = NULL;

  char *device = NULL;

  printf("SpringCard SDK for K531/SpringProx-CF/CSB Legacy\n");
  printf("\n");
  printf("NXP DESFIRE reference demo (DES/3DES only)\n");
  printf("------------------------------------------\n");
  printf("www.springcard.com\n\n");

  for (i=1; i<argc; i++)
  {
    if (!strcmp(argv[i], "-b0")) want_dsi_dri = 0; else
    if (!strcmp(argv[i], "-b1")) want_dsi_dri = 1; else
    if (!strcmp(argv[i], "-b2")) want_dsi_dri = 2; else
    if (!strcmp(argv[i], "-b3")) want_dsi_dri = 3; else
    if (i == argc-1)
    {
      device = argv[i];
      printf("Device : '%s'\n", device);
    } else
    {
      printf("usage: ref_desfire [-b0|-b1|-b2|-b3] [device]\n");
      printf("       -b0 : set baudrate to 106kbit/s\n");
      printf("       -b1 : set baudrate to 212kbit/s\n");
      printf("       -b2 : set baudrate to 424kbit/s\n");
      printf("       -b3 : set baudrate to 848kbit/s\n");
      printf("\n");
      return 0;
    }
  }

  rc = SPROXx_GetLibrary(s_buffer, sizeof(s_buffer));
  if (rc != MI_OK)
  {
    printf("Failed to get API version\n");
    goto done;
  }
  printf("API version : %s\n", s_buffer);
  printf("\n");
  
  rInst = SPROXx_CreateInstance();
  if (rInst == NULL)
  {
    printf("Out of memory\n");
    goto done;
  }
    
  rc = SPROXx_AttachDesfireLibrary(rInst);
  if (rc != MI_OK)
  {
    printf("Failed to initialize sprox_desfire_ex library\n");
    goto done;     
  }

#ifdef LOOP_TEST
  for (;;)
  {
#endif

    /* Open reader */
    /* ----------- */
  
    rc = SPROXx_ReaderOpen(rInst, device);
    if (rc != MI_OK)
    {
      printf("Reader not found\n");
      goto done;
    }
  
    rc = SPROXx_ReaderGetDevice(rInst, s_buffer, sizeof(s_buffer));
    if (rc == MI_OK)
      printf("Reader found on %s\n", s_buffer);
  
    rc = SPROXx_ReaderGetFirmware(rInst, s_buffer, sizeof(s_buffer));
    if (rc == MI_OK)
      printf("Reader firwmare is %s\n", s_buffer);

    /* Configure reader in ISO 14443-A mode */
    /* ------------------------------------ */
    rc = SPROXx_SetConfig(rInst, CFG_MODE_ISO_14443_A);
    if (rc != MI_OK)
    {
      printf("Failed to configure the reader\n");
      goto close;
    }

    /* RF field ON */
    SPROXx_ControlRF(rInst, TRUE);

    /* Select any tag in the ISO 14443-A RF field */
    /* ------------------------------------------ */
  next_tag:

    printf("Waiting for a tag...\n");

    rc = SPROXx_TclA_ActivateIdle(rInst, atq, snr, &snrlen, sak);
    if (rc == MI_CARD_NOT_TCL)
    {
      /* On a bien trouve un badge, mais il s'arrete au type 3 */
      printf("The selected tag is not ISO 14443-4 (T=CL)\n");
      goto tag_halt;
    }
    if (rc == MI_NOTAGERR)
    {
      /* Pas de badge dans le champ */
      printf("No available tag in RF field\n");
      goto close;
    }
    if (rc != MI_OK)
    {
      /* Erreur */
      printf("Failed to select tag\n");
      goto close;
    }

    printf("T=CL tag found, SNR=");
    for (i = 0; i < snrlen; i++)
      printf("%02X", snr[i]);
    printf(" ATQ=%02X%02X SAK=%02X\n", atq[1], atq[0], sak[0]);

    /* Is the tag a DESFire ? */
    /* ---------------------- */
    if ((snr[0] != 0x04) || (atq[1] != 0x03) || (atq[0] != 0x44))
    {
      printf("This is not a DESFire tag\n");
      goto tag_halt;
    }

    /* Open a T=CL session on the tag */
    /* ------------------------------ */
    rc = SPROXx_TclA_GetAts(rInst, cid, ats, &atslen);
    if (rc != MI_OK)
    {
      /* Erreur */
      printf("Failed to activate the tag (%d)\n", rc);
      goto tag_halt;
    }

    printf("T=CL tag activated, ATS=");
    for (i = 0; i < atslen; i++)
      printf("%02X", ats[i]);
    printf(" (TA1=%02X TA2=%02X TA3=%02X)\n", ats[2], ats[3], ats[4]);

    /* PPS is not really interesting since we stay at 106kbps */
    rc = SPROXx_TclA_Pps(rInst, cid, want_dsi_dri, want_dsi_dri);
    if (rc != MI_OK)
    {
      /* Erreur */
      printf("Failed to negociate PPS (DSI=DRI=%d)\n", want_dsi_dri);
      goto tag_stop;
    }
    printf("PPS OK, DSI=DRI=%d\n", want_dsi_dri);

    /* Check DESFire library functions */
    /* ------------------------------- */

    {

      SWORD rc;
      SDWORD lAmount;
      BYTE bCommMode, bKeyVersion;
      DWORD eNBytesRead, eNRecordsRead, eOffset;
      BYTE abCardMasterKey[16];
      BYTE bStdDataFileID, bFileType, bNFilesFound, bNApplicationsFound;
      BYTE temp;
      BYTE abDataBuffer[550];
      WORD wDesFireSoftwareVersion, wAccessRights;
      int i, iTransaction, iFileIndex;

      DF_VERSION_INFO stVersionInfo;
      DF_ADDITIONAL_FILE_SETTINGS unFileSettings;

    next_run:

      //  After activating a DesFire card the currently selected 'application' is the card
      //  level (AID = 0). Therefore the next command is redundant.
      //  We use the command to check that the card is responding correctly.
      rc = SPROXx_Desfire_SelectApplication(rInst, 0);
      CHECK_RC();

      //  Get the card's version information.
      rc = SPROXx_Desfire_GetVersion(rInst, &stVersionInfo);
      CHECK_RC();
      wDesFireSoftwareVersion =
        (unsigned int) ((unsigned int) stVersionInfo.
                        bSwMajorVersion << 8 | stVersionInfo.bSwMinorVersion);


      //  Which Card Master Key is currently in use ?
      //  Beginning with DesFire version 0.1 the GetKeyVersion command can help determining
      //  which key is currently effective.
      rc = SPROXx_Desfire_GetKeyVersion(rInst, 0, &bKeyVersion);
      CHECK_RC();

      //  Authenticate with the key which corresponds to the retieved key version.
      if (bKeyVersion == 0)
        rc = SPROXx_Desfire_Authenticate(rInst, 0, abNullKey);
      else if (bKeyVersion == 0xAA)
        rc = SPROXx_Desfire_Authenticate(rInst, 0, ab1DesKey);
      else if (bKeyVersion == 0xC7)
        rc = SPROXx_Desfire_Authenticate(rInst, 0, ab3DesKey);
      else
      {
        //  Who knows the key ?
        printf("Sorry, the master key is unknown (version = %02X)\n",
               bKeyVersion);
        goto tag_stop;
      }
      CHECK_RC();

      if (bKeyVersion != 0x00)
      {
        printf("Current master key version is %02X\n", bKeyVersion);
        rc = SPROXx_Desfire_GetKeySettings(rInst, &abDataBuffer[0], &abDataBuffer[1]);
        CHECK_RC();
        printf("Root application key settings are %02X %02X\n",
               abDataBuffer[0], abDataBuffer[1]);

        //  Try to allow to change the key
        rc = SPROXx_Desfire_ChangeKeySettings(rInst, 0xF);
        CHECK_RC();

        //  Back to blank key
        rc = SPROXx_Desfire_ChangeKey(rInst, 0, abNullKey, NULL);
        CHECK_RC();

        //  Authenticate again
        rc = SPROXx_Desfire_Authenticate(rInst, 0, abNullKey);
        CHECK_RC();

        //  Startup with a blank card !!!
        printf("Formatting the tag\n");
        rc = SPROXx_Desfire_FormatPICC(rInst);
        CHECK_RC();

        goto next_run;
      }
      //  Change the Card master key to a SingleDES key.
      memcpy(abCardMasterKey, ab1DesKey, 16);
      rc = SPROXx_Desfire_ChangeKey(rInst, 0, abCardMasterKey, NULL);
      CHECK_RC();
      rc = SPROXx_Desfire_GetKeyVersion(rInst, 0, &bKeyVersion);
      CHECK_RC();
      rc = SPROXx_Desfire_Authenticate(rInst, 0, abCardMasterKey);
      CHECK_RC();

      //  Change the Card master key to a TripleDES key.
      memcpy(abCardMasterKey, ab3DesKey, 16);
      rc = SPROXx_Desfire_ChangeKey(rInst, 0, abCardMasterKey, NULL);
      CHECK_RC();
      rc = SPROXx_Desfire_GetKeyVersion(rInst, 0, &bKeyVersion);
      CHECK_RC();
      rc = SPROXx_Desfire_Authenticate(rInst, 0, abCardMasterKey);
      CHECK_RC();

      //  At this point we would like to begin with a blank card.
      rc = SPROXx_Desfire_FormatPICC(rInst);
      CHECK_RC();

      //  Create three applications:

      //  Authentication is not necessary in the default configuration.
      //  Clear the authentication state to show this.
      rc = SPROXx_Desfire_SelectApplication(rInst, 0);
      CHECK_RC();

      //  Application A is the most open one.
      //  It has no keys and its key settings are least restrictive.
      //  Note: since there are no keys, the Change Keys key settting must be assigned
      //        the value 0xE or 0xF.
      rc = SPROXx_Desfire_CreateApplication(rInst, 0xAAAAAA, 0xFF, 0);
      CHECK_RC();

      //  Application B's key settings can be changed at a later time.
      //  It has six keys.
      //  Authentication with a given key allows also to change that key.
      //  (the Change Keys key settting is 0xE)
      rc = SPROXx_Desfire_CreateApplication(rInst, 0xBBBBBB, 0xEF, 6);
      CHECK_RC();

      //  Application C keeps everything private.
      //  Even getting its file directory is not publicly allowed.
      //  The application has the maximum of 14 keys.
      //  We make key #0xC the Change Keys key.
      rc = SPROXx_Desfire_CreateApplication(rInst, 0xCCCCCC, 0xC0, 14);
      CHECK_RC();

      //  Verify, that the applications which have been just created exist.
      rc = SPROXx_Desfire_GetApplicationIDs(rInst, 10, (DWORD *) abDataBuffer, &temp);
      CHECK_RC();

      //  Create the files in application A:
      //  Since the application does not have any keys associated with it, the file access rights
      //  settings 0xE (public access granted) and 0xF (access denied) are the only permissable
      //  ones.
      rc = SPROXx_Desfire_SelectApplication(rInst, 0xAAAAAA);
      CHECK_RC();

      //  Create a the Standard Data file.
      bStdDataFileID = 15;
      rc =
        SPROXx_Desfire_CreateStdDataFile(rInst, bStdDataFileID, 0, 0xEEEE,
                                      sizeof(abDataBuffer));
      CHECK_RC();

      //  Create a 64 byte Backup file.
      rc = SPROXx_Desfire_CreateBackupDataFile(rInst, 5, 0, 0xEEEE, 64);
      CHECK_RC();

      //  Create a Value file allowing values from 0 to 1000.
      //  The initial value is 0.
      //  The Limited Credit feature is disabled.
      rc = SPROXx_Desfire_CreateValueFile(rInst, 4, 0, 0xEEEE, 0, 1000, 0, 0);
      CHECK_RC();

      //  And finally create a Cyclic Record file capable of holding 10 records of 4 bytes each.
      rc = SPROXx_Desfire_CreateCyclicRecordFile(rInst, 0, 0, 0xEEEE, 4, 10);
      CHECK_RC();

      //  Fill the Standard Data file with some data.
      memset(abDataBuffer, 0xCC, sizeof(abDataBuffer));
      rc =
        SPROXx_Desfire_WriteData(rInst, bStdDataFileID, DF_COMM_MODE_PLAIN, 0,
                              sizeof(abDataBuffer), abDataBuffer);
      CHECK_RC();
      rc =
        SPROXx_Desfire_WriteData(rInst, bStdDataFileID, DF_COMM_MODE_PLAIN, 0, 30,
                              (unsigned char *)
                              "This is the 1st block written.");
      CHECK_RC();
      rc =
        SPROXx_Desfire_WriteData(rInst, bStdDataFileID, DF_COMM_MODE_PLAIN, 34, 22,
                              (unsigned char *) "This is the 2nd block.");
      CHECK_RC();

      //  Then make the file permanently read-only.
      rc =
        SPROXx_Desfire_ChangeFileSettings(rInst, bStdDataFileID, DF_COMM_MODE_PLAIN,
                                       0xEFFF);
      CHECK_RC();

      //  Read part of the file's contents.
      rc =
        SPROXx_Desfire_ReadData(rInst, bStdDataFileID, DF_COMM_MODE_PLAIN, 10, 50,
                             abDataBuffer, &eNBytesRead);
      CHECK_RC();

      //  Get all data in one block. 
      //  Note: Must make sure that buffer is large enough for all data!!
      rc =
        SPROXx_Desfire_ReadData(rInst, bStdDataFileID, DF_COMM_MODE_PLAIN, 0, 0,
                             abDataBuffer, &eNBytesRead);
      CHECK_RC();

      //  Try to overwrite the file.
      //  Since we have made the file read-only, this should fail.
      rc =
        SPROXx_Desfire_WriteData(rInst, bStdDataFileID, DF_COMM_MODE_PLAIN, 20, 5,
                              (unsigned char *) "Test!");
      if (rc != (DFCARD_ERROR - DF_PERMISSION_DENIED))
        CHECK_RC();

      //  Do 15 transactions.
      for (iTransaction = 0; iTransaction < 15; iTransaction++)
      {
        //  Write to the Backup Data file.
        sprintf((char *) abDataBuffer, "%02d,", iTransaction);
        rc =
          SPROXx_Desfire_WriteData(rInst, 5, DF_COMM_MODE_PLAIN, 3 * iTransaction, 3,
                                abDataBuffer);
        CHECK_RC();

        //  Manipulate the Value file.
        rc = SPROXx_Desfire_Credit(rInst, 4, DF_COMM_MODE_PLAIN, 100);
        CHECK_RC();
        rc = SPROXx_Desfire_Debit(rInst, 4, DF_COMM_MODE_PLAIN, 93);
        CHECK_RC();

        //  Write to the Cyclic Record file.
        rc =
          SPROXx_Desfire_WriteRecord(rInst, 0, DF_COMM_MODE_PLAIN, 2, 2, abDataBuffer);
        CHECK_RC();
        //  The following Write Record will write to the same record as above
        rc =
          SPROXx_Desfire_WriteRecord(rInst, 0, DF_COMM_MODE_PLAIN, 0, 2,
                                  (unsigned char *) "r.");
        CHECK_RC();

        //  Verify that the 'official' contents of the three files has not changed
        //  before the CommitTransaction command.
        //  Must make sure that buffer is large enough for all data!
        rc =
          SPROXx_Desfire_ReadData(rInst, 5, DF_COMM_MODE_PLAIN, 0, 0, abDataBuffer,
                               &eNBytesRead);
        CHECK_RC();
        rc = SPROXx_Desfire_GetValue(rInst, 4, DF_COMM_MODE_PLAIN, &lAmount);
        CHECK_RC();
        //  Note: reading from an empty record file returns an error.
        //        beginning with version 0.1 this aborts the transaction.
        if (iTransaction != 0)
        {
          rc =
            SPROXx_Desfire_ReadRecords(rInst, 0, DF_COMM_MODE_PLAIN, 0, 0, 4,
                                    abDataBuffer, &eNRecordsRead);
          CHECK_RC();
        }
        //  Declare the transaction valid.
        rc = SPROXx_Desfire_CommitTransaction(rInst);
        CHECK_RC();

        //  Verify that the transaction has become effective.
        //  Note: Must make sure that buffer is large enough for all data!
        rc =
          SPROXx_Desfire_ReadData(rInst, 5, DF_COMM_MODE_PLAIN, 0, 0, abDataBuffer,
                               &eNBytesRead);
        CHECK_RC();
        rc = SPROXx_Desfire_GetValue(rInst, 4, DF_COMM_MODE_PLAIN, &lAmount);
        CHECK_RC();
        rc =
          SPROXx_Desfire_ReadRecords(rInst, 0, DF_COMM_MODE_PLAIN, 0, 0, 4,
                                  abDataBuffer, &eNRecordsRead);
        CHECK_RC();
      }

      //  Limited Credit has been disabled, so the following call should fail.
      rc = SPROXx_Desfire_LimitedCredit2(rInst, 4, 20);
      if (rc != (DFCARD_ERROR - DF_PERMISSION_DENIED))
        CHECK_RC();

      //  Get the file IDs of the current application.
      rc = SPROXx_Desfire_GetFileIDs(rInst, 15, abDataBuffer, &bNFilesFound);
      CHECK_RC();

      //  Get information about the application's files.
      //  Delete each file after retrieving information about it.
      for (iFileIndex = 0; iFileIndex < bNFilesFound; iFileIndex++)
      {
        rc =
          SPROXx_Desfire_GetFileSettings(rInst, abDataBuffer[iFileIndex], &bFileType,
                                      &bCommMode, &wAccessRights,
                                      &unFileSettings);
        CHECK_RC();
        rc = SPROXx_Desfire_DeleteFile(rInst, abDataBuffer[iFileIndex]);
        CHECK_RC();
      }

      //  Verify that there are no files in the application.
      rc = SPROXx_Desfire_GetFileIDs(rInst, 15, abDataBuffer, &bNFilesFound);
      CHECK_RC();

      //  Delete application A.
      //  Since this application doesn't have an Application Master Key,
      //  this requires Card Master Key authentication.
      rc = SPROXx_Desfire_SelectApplication(rInst, 0);
      CHECK_RC();
      rc = SPROXx_Desfire_Authenticate(rInst, 0, abCardMasterKey);
      CHECK_RC();
      rc = SPROXx_Desfire_DeleteApplication(rInst, 0xAAAAAA);
      CHECK_RC();

      //  Verify that application A has been deleted.
      rc =
        SPROXx_Desfire_GetApplicationIDs(rInst, 10, (DWORD *) abDataBuffer,
                                      &bNApplicationsFound);
      CHECK_RC();

      //  Changing application B's keys:
      rc = SPROXx_Desfire_SelectApplication(rInst, 0xBBBBBB);
      CHECK_RC();

      //  Use a TripleDES key as the Application Master Key.
      rc = SPROXx_Desfire_Authenticate(rInst, 0, abNullKey);
      CHECK_RC();
      rc = SPROXx_Desfire_ChangeKey(rInst, 0, (unsigned char *) "App.B Master Key", NULL);
      CHECK_RC();

      //  Beginning with DesFire version 0.1 we can query the version number of a key.
      rc = SPROXx_Desfire_GetKeyVersion(rInst, 0, &bKeyVersion);
      CHECK_RC();

      //  Authenticate with the new application master key.
      //  This time use the opposite parity in all key bytes.
      rc = SPROXx_Desfire_Authenticate(rInst, 0, (unsigned char *) "@qq/C!L`ruds!Kdx");
      CHECK_RC();

      //  Change key #1 to a different SingleDES key (both key halves are the same).
      //  Authentication with that key is necessary for changing it.
      rc = SPROXx_Desfire_Authenticate(rInst, 1, abNullKey);
      CHECK_RC();
      rc = SPROXx_Desfire_ChangeKey(rInst, 1, (unsigned char *) "SglDES_1SglDES_1", NULL);
      CHECK_RC();

      //  Change key #5 to a TripeDES key.
      //  Authentication with that key is necessary for changing it.
      rc = SPROXx_Desfire_Authenticate(rInst, 5, abNullKey);
      CHECK_RC();
      rc = SPROXx_Desfire_ChangeKey(rInst, 5, (unsigned char *) "B's Chg Keys Key", NULL);
      CHECK_RC();

      //  Make key #5 the Change Keys Key.
      rc = SPROXx_Desfire_Authenticate(rInst, 0, (unsigned char *) "App.B Master Key");
      CHECK_RC();
      rc = SPROXx_Desfire_ChangeKeySettings(rInst, 0x5F);
      CHECK_RC();

      //  Verify the new key settings.
      rc = SPROXx_Desfire_GetKeySettings(rInst, &abDataBuffer[0], &abDataBuffer[1]);
      CHECK_RC();

      //  Change keys #1 through #4 using the three key procedure.
      //  Authentication with the Change Keys Key is now necessary for changing ordinary keys.
      rc = SPROXx_Desfire_Authenticate(rInst, 5, (unsigned char *) "B's Chg Keys Key");
      CHECK_RC();
      rc =
        SPROXx_Desfire_ChangeKey(rInst, 1, (unsigned char *) "App.B Key #1.   ",
                              (unsigned char *) "SglDES_1SglDES_1");
      CHECK_RC();
      rc =
        SPROXx_Desfire_ChangeKey(rInst, 2, (unsigned char *) "App.B Key #2..  ",
                              abNullKey);
      CHECK_RC();
      rc =
        SPROXx_Desfire_ChangeKey(rInst, 3, (unsigned char *) "App.B Key #3... ",
                              abNullKey);
      CHECK_RC();
      rc =
        SPROXx_Desfire_ChangeKey(rInst, 4, (unsigned char *) "App.B Key #4....",
                              abNullKey);
      CHECK_RC();

      //  For demonstrating the three possible communication modes we create an instance
      //  of each basic file type:
      //  a Data file:  Read = 1, Write = 2, ReadWrite = 3, ChangeConfig = 4
      //  a Value file: Debit = 1, LimitedCredit = 3, Credit = 2, ChangeConfig = 4
      //  and a Linear Record file: Read = 1, Write = 3, ReadWrite = 2, ChangeConfig = 4
      //  Note: Must make sure that buffer is large enough for all data!
      bStdDataFileID--;
      rc = SPROXx_Desfire_CreateStdDataFile(rInst, bStdDataFileID, 0, 0x1234, 100);
      CHECK_RC();
      rc =
        SPROXx_Desfire_CreateValueFile(rInst, 4, 0, 0x1324, -987654321, -1000,
                                    -1000000, 1);
      CHECK_RC();
      rc = SPROXx_Desfire_CreateLinearRecordFile(rInst, 1, 0, 0x1324, 25, 4);
      CHECK_RC();

      //  Do 7 transactions.
      for (iTransaction = 0; iTransaction < 7; iTransaction++)
      {
        //  Change the communication mode for all files.
        bCommMode = iTransaction % 3;
        if (bCommMode == 2)
          bCommMode++;

        //  This requires authentication with the key defined for changing the configuration.
        rc =
          SPROXx_Desfire_Authenticate(rInst, 4, (unsigned char *) "App.B Key #4....");
        CHECK_RC();
        rc =
          SPROXx_Desfire_ChangeFileSettings(rInst, bStdDataFileID, bCommMode, 0x1234);
        CHECK_RC();
        rc = SPROXx_Desfire_ChangeFileSettings(rInst, 4, bCommMode, 0x1324);
        CHECK_RC();
        rc = SPROXx_Desfire_ChangeFileSettings(rInst, 1, bCommMode, 0x1324);
        CHECK_RC();

        //  Authenticate with the key which allows writing to files and increasing the Value
        //  file's value.
        rc =
          SPROXx_Desfire_Authenticate(rInst, 2, (unsigned char *) "App.B Key #2..  ");
        CHECK_RC();

        //  Write to the Standard Data file.
        for (i = 0; i < 100; i++)
          abDataBuffer[i] = iTransaction + i;
        rc =
          SPROXx_Desfire_WriteData(rInst, bStdDataFileID, bCommMode, 0, 100,
                                abDataBuffer);
        CHECK_RC();
        sprintf((char *) abDataBuffer, " Transaction #%d ", iTransaction);
        rc =
          SPROXx_Desfire_WriteData(rInst, bStdDataFileID, bCommMode, 5,
                                strlen((char *) abDataBuffer), abDataBuffer);
        CHECK_RC();

        //  Write to the Linear Record file.
        //  If it turns out, that the file is full, clear its contents and repeat writing.
        for (i = 0; i < 2; i++)
        {
          rc =
            SPROXx_Desfire_WriteRecord(rInst, 1, bCommMode, 0, 25,
                                    (unsigned char *)
                                    "0123456789012345678901234");
          if (rc == 0)
          {
            sprintf((char *) abDataBuffer, " Transaction #%d ", iTransaction);
            rc =
              SPROXx_Desfire_WriteRecord(rInst, 1, bCommMode, 5,
                                      strlen((char *) abDataBuffer),
                                      abDataBuffer);
          }
          //  Was the WriteRecord successful ?
          if (rc == 0)
            break;              // yes

          //  Clear the record file.
          rc = SPROXx_Desfire_ClearRecordFile(rInst, 1);
          CHECK_RC();

          //  It is not allowed to write to the file before a CommitTransaction.
          //  So the following call will fail !
          rc =
            SPROXx_Desfire_WriteRecord(rInst, 1, bCommMode, 5,
                                    strlen((char *) abDataBuffer),
                                    abDataBuffer);
          if (rc != (DFCARD_ERROR - DF_PERMISSION_DENIED))
            CHECK_RC();

          //  Version 0.1 and above execute an implicit AbortTransaction after any
          //  error. Therefore the ClearRecordFile has been cancelled. We have to repeat it.
          rc = SPROXx_Desfire_ClearRecordFile(rInst, 1);
          CHECK_RC();

          //  After the following the Record file is again ready for data.
          rc = SPROXx_Desfire_CommitTransaction(rInst);
          CHECK_RC();
        }

        //  Modify the Value file.
        rc = SPROXx_Desfire_Debit(rInst, 4, bCommMode, 1300);
        CHECK_RC();
        rc = SPROXx_Desfire_Credit(rInst, 4, bCommMode, 20);
        CHECK_RC();
        rc = SPROXx_Desfire_Debit(rInst, 4, bCommMode, 1700);
        CHECK_RC();

        //  Make all changes current.
        rc = SPROXx_Desfire_CommitTransaction(rInst);
        CHECK_RC();

        //  Return the whole debited amount to the Value File.
        rc = SPROXx_Desfire_LimitedCredit(rInst, 4, bCommMode, 3000);
        CHECK_RC();

        //  Make the change current.
        rc = SPROXx_Desfire_CommitTransaction(rInst);
        CHECK_RC();


        //  Authenticate with the key which allows reading files and retrieving the Value
        //  file's value.
        rc =
          SPROXx_Desfire_Authenticate(rInst, 1, (unsigned char *) "App.B Key #1.   ");
        CHECK_RC();

        //  Read the first half of the Standard Data file's data specifying the exact
        //  number of bytes to read.
        rc =
          SPROXx_Desfire_ReadData(rInst, bStdDataFileID, bCommMode, 0, 50,
                               abDataBuffer, &eNBytesRead);
        CHECK_RC();
        //  Read the second half of the data with an open read (give me all data available).
        rc =
          SPROXx_Desfire_ReadData(rInst, bStdDataFileID, bCommMode, 50, 0,
                               abDataBuffer, &eNBytesRead);
        CHECK_RC();

        //  Get the Value file's current balance.
        rc = SPROXx_Desfire_GetValue(rInst, 4, bCommMode, &lAmount);
        CHECK_RC();

        //  Get the number of records in the Linear Record file.
        rc = SPROXx_Desfire_GetFileSettings(rInst, 1, 0, 0, 0, &unFileSettings);
        CHECK_RC();

        //  Read the oldest record from the file.
        rc =
          SPROXx_Desfire_ReadRecords(rInst, 1, bCommMode,
                                  unFileSettings.stRecordFileSettings.
                                  eCurrNRecords - 1, 1,
                                  unFileSettings.stRecordFileSettings.
                                  eRecordSize, abDataBuffer, &eNRecordsRead);
        CHECK_RC();

        //  Read all records from the file.
        rc =
          SPROXx_Desfire_ReadRecords(rInst, 1, bCommMode, 0, 0,
                                  unFileSettings.stRecordFileSettings.
                                  eRecordSize, abDataBuffer, &eNRecordsRead);
        CHECK_RC();
      }

      //  Get the file IDs of the current application.
      rc = SPROXx_Desfire_GetFileIDs(rInst, 16, abDataBuffer, &bNFilesFound);
      CHECK_RC();

      //  Get information about the application's files.
      //  Delete each file after retrieving information about it.
      for (iFileIndex = 0; iFileIndex < bNFilesFound; iFileIndex++)
      {
        rc =
          SPROXx_Desfire_GetFileSettings(rInst, abDataBuffer[iFileIndex], &bFileType,
                                      &bCommMode, &wAccessRights,
                                      &unFileSettings);
        CHECK_RC();
        rc = SPROXx_Desfire_DeleteFile(rInst, abDataBuffer[iFileIndex]);
        CHECK_RC();
      }

      //  Verify that there are no files in the application.
      rc = SPROXx_Desfire_GetFileIDs(rInst, 16, abDataBuffer, &bNFilesFound);
      CHECK_RC();

      //  Delete application B.
      //  This time we can (and do) use the Application Master Key.
      rc = SPROXx_Desfire_Authenticate(rInst, 0, (unsigned char *) "App.B Master Key");
      CHECK_RC();
      rc = SPROXx_Desfire_DeleteApplication(rInst, 0xBBBBBB);
      CHECK_RC();

      //  Verify that application B has been deleted.
      rc = SPROXx_Desfire_GetApplicationIDs(rInst, 10, (DWORD *) abDataBuffer, &temp);
      CHECK_RC();

      //  Working with a larger file (a Cyclic Record File) using application C:
      rc = SPROXx_Desfire_SelectApplication(rInst, 0xCCCCCC);
      CHECK_RC();

      //  Define keys #1 and #2 using the Change Keys key (#12).
      rc = SPROXx_Desfire_Authenticate(rInst, 12, abNullKey);
      CHECK_RC();

      rc =
        SPROXx_Desfire_ChangeKey(rInst, 1, (unsigned char *) "App.C Key #1.   ",
                              abNullKey);
      CHECK_RC();

      rc =
        SPROXx_Desfire_ChangeKey(rInst, 2, (unsigned char *) "App.C Key #2..  ",
                              abNullKey);
      CHECK_RC();

      //  Create the file.
      rc = SPROXx_Desfire_Authenticate(rInst, 0, abNullKey);
      CHECK_RC();

      rc = SPROXx_Desfire_CreateCyclicRecordFile(rInst, 6, 0, 0x12E0, 100, 22);
      CHECK_RC();

      //  Do 50 transactions.
      for (iTransaction = 0; iTransaction < 50; iTransaction++)
      {
        //  Change the file's communication mode.
        bCommMode = (iTransaction % 3);
        if (bCommMode == 2)
          bCommMode++;

        //  This requires authentication with the key defined for changing the configuration.
        //  For this file it is the Application Master Key.
        rc = SPROXx_Desfire_Authenticate(rInst, 0, abNullKey);
        CHECK_RC();
        rc = SPROXx_Desfire_ChangeFileSettings(rInst, 6, bCommMode, 0x12E0);
        CHECK_RC();

        //  The file can be written using either the Write access key (0x.2..) or the
        //  Read/Write key (0x..E.).
        //  A valid authentication with key #2 causes the communication to take place in
        //  the mode defined with ChangeFileSettings above.
        //  Not being authenticated with key #2 causes the Read/Write access right to be used
        //  forcing the communication to plain mode.
        if (iTransaction & 4)
        {
          rc =
            SPROXx_Desfire_Authenticate(rInst, 2, (unsigned char *) "App.C Key #2..  ");
          CHECK_RC();
        } else
          bCommMode = 0;

        //  Write a new record.
        memset(abDataBuffer, '_', 100);
        abDataBuffer[0] = iTransaction;
        abDataBuffer[99] = iTransaction;
        sprintf((char *) abDataBuffer + 5, " Transaction #%d ", iTransaction);
        rc = SPROXx_Desfire_WriteRecord(rInst, 6, bCommMode, 0, 100, abDataBuffer);

        //  Cancel every 7th WriteRecord operation.
        if (iTransaction % 7 == 0)
          rc = SPROXx_Desfire_AbortTransaction(rInst);
        else
          rc = SPROXx_Desfire_CommitTransaction(rInst);
        if (rc != (DFCARD_ERROR - DF_NO_CHANGES))
          if (rc != (DFCARD_ERROR - DF_COMMAND_ABORTED))
            CHECK_RC();
      }

      //  Read each individual record using the designated read key.
      //  Note that increasing the offset lets us go back in the record history.
      //  Note also that only 22-1 records (one less than specified in CreateCyclicRecordFile)
      //  can be accessed.
      bCommMode = 1;
      rc = SPROXx_Desfire_Authenticate(rInst, 1, (unsigned char *) "App.C Key #1.   ");
      CHECK_RC();
      for (eOffset = 0; eOffset < 22; eOffset++)
      {
        rc =
          SPROXx_Desfire_ReadRecords(rInst, 6, bCommMode, eOffset, 1, 100,
                                  abDataBuffer, &eNRecordsRead);
        if (rc != (DFCARD_ERROR - DF_BOUNDARY_ERROR))
          CHECK_RC();
      }

      //  Read the whole record file with a single ReadRecords call.
      //rc = SPROXx_Desfire_ReadRecords( 6, bCommMode, 0, 0, 100, abDataBuffer, &eNRecordsRead );
      //CHECK_RC();

      //  Change the master key settings such that master key authentication will be required
      //  for all card operations.
      //  Leave the ChangeConfiguration bit (bit 3) set to allow undoing the change.
      rc = SPROXx_Desfire_SelectApplication(rInst, 0);
      CHECK_RC();
      rc = SPROXx_Desfire_Authenticate(rInst, 0, abCardMasterKey);
      CHECK_RC();
      rc = SPROXx_Desfire_ChangeKeySettings(rInst, 0x8);
      CHECK_RC();

      //  Clear the authentication state and try to get application IDs.
      //  Also try to delete application C or to create a new application.
      rc = SPROXx_Desfire_SelectApplication(rInst, 0);
      CHECK_RC();
      //  The following three calls will report an Authentication Error (0xAE).
      rc = SPROXx_Desfire_GetApplicationIDs(rInst, 10, (DWORD *) abDataBuffer, &temp);
      if (rc != (DFCARD_ERROR - DF_AUTHENTICATION_ERROR))
        CHECK_RC();
      rc = SPROXx_Desfire_DeleteApplication(rInst, 0xCCCCCC);
      if (rc != (DFCARD_ERROR - DF_AUTHENTICATION_ERROR))
        CHECK_RC();
      rc = SPROXx_Desfire_CreateApplication(rInst, 0xDDDDDD, 0xEF, 0);
      if (rc != (DFCARD_ERROR - DF_AUTHENTICATION_ERROR))
        CHECK_RC();

      //  With authentication all three should work.
      rc = SPROXx_Desfire_Authenticate(rInst, 0, abCardMasterKey);
      CHECK_RC();
      rc = SPROXx_Desfire_GetApplicationIDs(rInst, 10, (DWORD *) abDataBuffer, &temp);
      CHECK_RC();
      rc = SPROXx_Desfire_DeleteApplication(rInst, 0xCCCCCC);
      CHECK_RC();
      rc = SPROXx_Desfire_CreateApplication(rInst, 0xDDDDDD, 0xEF, 0);
      CHECK_RC();

      //  Change the master key settings back to the default which is least restrictive.
      rc = SPROXx_Desfire_ChangeKeySettings(rInst, 0xF);
      CHECK_RC();

      //  Change the Card master key back to the 0 key.
      rc = SPROXx_Desfire_Authenticate(rInst, 0, abCardMasterKey);
      CHECK_RC();
      rc = SPROXx_Desfire_ChangeKey(rInst, 0, abNullKey, NULL);
      CHECK_RC();

      //  Delete all demonstration data from the card.
      rc = SPROXx_Desfire_Authenticate(rInst, 0, abNullKey);
      CHECK_RC();
      rc = SPROXx_Desfire_FormatPICC(rInst);
      CHECK_RC();

    }

    printf("\n");
    printf("All tests have been successfully passed\n");

    goto tag_stop;

  tag_stop:

    /* T=CL (ISO 14443-4) tag stop */
    /* --------------------------- */

    rc = SPROXx_TclA_Deselect(rInst, cid);
    if (rc != MI_OK)
    {
      printf("T=CL DESELECT failed (%d)\n", rc);
      goto tag_halt;
    }

  tag_halt:

    /* ISO 14443-3 tag stop */
    /* -------------------- */

    rc = SPROXx_TclA_Halt(rInst);
    if (rc != MI_OK)
    {
      printf("HALT failed\n");
      goto close;
    }

    /* Another tag in the field ? */
    /* -------------------------- */
    goto next_tag;

  close:
    SPROXx_ControlRF(rInst, FALSE);
    SPROXx_ReaderClose(rInst);

  done:
    /* Display last error */
    if (rc == MI_OK)
    {
      printf("Done\n");
    } else
    {
      printf("%s (%d)\n", SPROXx_GetErrorMessage(rc), rc);
    }
#ifdef LOOP_TEST
    loop_count++;
    printf("--> %d error(s) after %d loop(s)\n", err_count, loop_count);
  }
#endif

  if (rInst != NULL)
  {
    SPROXx_DetachDesfireLibrary(rInst);
    SPROXx_DestroyInstance(rInst);    
  }
  return 0;
}
